home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / DAKIT.ZIP / ANIMA.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-05-15  |  26.7 KB  |  1,096 lines

  1. ;-----------------------------------------------------------------
  2. ; anima.asm
  3. ; ---------
  4. ; Assembly Anim stuff.
  5. ;-----------------------------------------------------------------
  6.  
  7.     include asm.inc
  8.     include anim.inc
  9.  
  10.     HEADER anima
  11.  
  12.     extrn _printf:far
  13. ;-----------------------------------------------------------------
  14.  
  15.     DSEG
  16.  IF 0
  17.     extrn    _doDump:byte
  18.     public  _TotBytes
  19. runMsg  db    'run %x',13,0
  20. dumpMsg  db    'dump %x',13,0
  21. skipMsg  db    'skip %x',13,0
  22. clipMsg db    '---dest:%x ',0
  23. finalMsg db    '---dest:%x last-row-bytes:%x--- ',0
  24. _TotBytes dw     0
  25.   ENDIF
  26.     ENDDS
  27.  
  28.     PSEG anima
  29.  
  30. ;-----------------------------------------------------------------
  31. ; void ShortDelay(UWORD delay);
  32. ; Does a high-speed delay loop.
  33. ;-----------------------------------------------------------------
  34.  
  35.     public _ShortDelay
  36.     STARTPROC _ShortDelay
  37.  
  38. SD_DELAY    = ARGB
  39.  
  40.     push    bp
  41.     mov    bp,sp
  42.  
  43.     mov    cx,SD_DELAY[bp]
  44. sd_loop:
  45.     loop    sd_loop
  46.  
  47.     pop    bp
  48.     ret
  49.  
  50.     ENDPROC _ShortDelay
  51.  
  52.  
  53.  IF 1    ; RunSkipDump format.
  54. ;-----------------------------------------------------------------
  55. ; UWORD PlayRunSkipDump(UWORD nBytes, srcSeg, srcAddr, dstSeg, dstAddr);
  56. ; Finishes playing the Bitmap body with type==RunSkipDump.
  57. ; RETURN final dstAddr (one byte past last pixel written).
  58. ; NOTE: since a final skip is omitted, this could be anywhere on the screen.
  59. ; If there is no final skip, it will be one past the last pixel on the screen.
  60. ; For a screen starting at address (offset) 0, its greatest value is
  61. ; the # pixels on the screen.
  62. ; NOTE: we're ignoring nBytes.  Bad data could cause this to write past
  63. ; end of dst buffer, or even to loop forever.
  64. ;-----------------------------------------------------------------
  65.  
  66.     public _PlayRunSkipDump
  67.     STARTPROC _PlayRunSkipDump
  68.  
  69. PR_N_BYTES    = ARGB
  70. PR_SRC_SEG    = ARGB+2
  71. PR_SRC_ADDR    = ARGB+4
  72. PR_DST_SEG    = ARGB+6
  73. PR_DST_ADDR    = ARGB+8
  74.  
  75.     push    bp
  76.     mov    bp,sp
  77.     push    si
  78.     push    di
  79.     push    es
  80.  
  81.     mov    si,PR_SRC_ADDR[bp]
  82.     mov    di,PR_DST_ADDR[bp]
  83.     mov    es,PR_DST_SEG[bp]
  84.  
  85.     push    ds            ; Save DS:DGROUP.
  86.     mov    ds,PR_SRC_SEG[bp]    ; SET DS:dstSeg.  NOT DGROUP.
  87.  
  88.     sub    ch,ch            ; SET CH = 0.
  89.     jmp    short nextOp
  90.  
  91. skip:
  92.     sub    cl,80h            ; Strip off sign bit, leaving skip cnt.
  93.     jz    longOp            ; cnt==0 indicates a long op.
  94. ; --- shortSkip ---
  95.     add    di,cx            ; skip # pixels.  (CH=0)
  96. ; --- variation on NEXTOP inline to minimize jmp's ---
  97. nextOp:                    ; Get and decode next op.
  98.     mov    cl,[si]
  99.     inc    si
  100.     jcxz    run
  101.     or    cl,cl            ; Test CL's sign bit.
  102.     jl    skip
  103. dump:
  104.     rep movsb            ; copy # pixels.  (CH=0)
  105. ; --- variation on NEXTOP inline to minimize jmp's ---
  106.     mov    cl,[si]
  107.     inc    si
  108.     or    cl,cl            ; Test CL's sign bit.
  109.     jl    skip
  110.     jg    dump
  111. run:
  112.     mov    cl,[si]            ; 8-bit unsigned count.
  113.     inc    si
  114.     lodsb                ; pixel value.
  115.     rep stosb            ; set # pixels to value.  (CH=0)
  116. ; --- variation on NEXTOP inline to minimize jmp's ---
  117.     mov    cl,[si]
  118.     inc    si
  119.     jcxz    run
  120.     or    cl,cl            ; Test CL's sign bit.
  121.     jl    skip
  122.     jmp    short dump
  123.  
  124. longOp:        ; NOTE: if load into CX, must clear CH afterwards.
  125.     lodsw                ; 16-bit unsigned count.
  126.     or    ax,ax            ; set flags.
  127.     jle    notLongSkip
  128. ;longSkip:
  129.     add    di,ax            ; skip # pixels.
  130.     jmp short nextOp
  131.         ; longSkip only used for > 2*127, so can't be very many,
  132.         ; so don't bother saving one jmp with inline NEXTOP.
  133.  
  134. notLongSkip:
  135.     jz    stop            ; long count of zero means "stop code".
  136.     mov    cx,ax            ; may SET CH non-zero.
  137.     sub    ch,80h            ; Clear sign bit.
  138.     cmp    ch,40h
  139.     jge    longRun
  140. ; --- For maximum speed on longDump, caller should insure src & dst are
  141. ; aligned.  To do so, caller must calculate whether
  142. ; src DATA will begin on same (odd or even) alignment as dst data.
  143. ; If not, first put a 1-byte Dump, which occupies 2 src bytes, thereby
  144. ; shifting relative alignment (src moves 2, dst moves 1).
  145. ;longDump
  146.     test    si,1            ; Insure src word-aligned.
  147.             ; In case caller didn't sync src & dst, we chose
  148.             ; to align src because we know it is of benefit --
  149.             ; aligning dst on 8-bit video cards might not be of
  150.             ; any benefit.
  151.     jz    dumpWordAligned
  152.     movsb                ; get to word boundary.
  153.     dec    cx
  154. dumpWordAligned:
  155.     shr    cx,1            ; Convert byte count to word count.
  156.     jc    dumpOddByte
  157.     rep movsw            ; Word-aligned.
  158. longOpDone:
  159.     sub    ch,ch            ; SET CH = 0.
  160.     jmp    short nextOp
  161.  
  162. dumpOddByte:
  163.     rep movsw            ; Word-aligned.
  164.     movsb
  165.     jmp    short longOpDone
  166.  
  167. longRun:
  168.     sub    ch,40h            ; Clear "longRun" bit.
  169.     lodsb
  170.     mov    ah,al            ; Replicate byte to word value.
  171.     test    di,1            ; Insure dst word-aligned.
  172.     jz    runWordAligned
  173.     stosb
  174.     dec    cx
  175. runWordAligned:
  176.     shr    cx,1            ; Convert byte count to word count.
  177.     jc    runOddByte
  178.     rep stosw            ; Word-aligned.
  179.     jmp    short longOpDone
  180.  
  181. runOddByte:
  182.     rep stosw            ; Word-aligned.
  183.     stosb
  184.     jmp    short longOpDone
  185.     
  186. stop:
  187.     pop    ds            ; Restore DS:DGROUP.
  188.  
  189.     mov    ax,di            ; RETURN final dstAddr.
  190.     pop    es
  191.     pop    di
  192.     pop    si
  193.     pop    bp
  194.     ret
  195.  
  196.     ENDPROC _PlayRunSkipDump
  197.  
  198.  
  199. ;-----------------------------------------------------------------
  200. ; UWORD MakeRunSkipDump(UWORD src1Seg, src2Seg, finalPixelAddr,
  201. ;        UWORD dstSeg, dstAddr, dstLimit, UWORD *nBytesP,
  202. ;        UWORD srcWidth, finalRowAddr, finalRowWidth,
  203. ;        BOOL inFinalRow, skipPermitted);
  204. ; Finishes making the Bitmap body with type==RunSkipDump.
  205. ; RETURN TRUE if fit in deltaX.
  206. ; SIDE_EFFECT: set deltaX.nBytes, store that many bytes at deltaX.(seg:addr).
  207. ; ASSUMES srcs start at Addr=0.
  208. ;-----------------------------------------------------------------
  209.  
  210. ADDR    = 0    ; Field-offsets within a far ptr.  16-bit-offset.
  211. SEGM    = 2    ;                   Segment.
  212.  
  213. ; --- registers ---
  214. ; AL: pixel.       Value of current src2 pixel.
  215. ; AH: runPix.       Value of pixels in current Run.
  216. ; BL: skipInDump.  # skippable bytes in Dump or Run.
  217. ; BH: runInDump.   # runnable bytes in Dump.
  218. ; CX: wordCnt.  # pixels processed for current op.
  219. ; DX: -- temporary.
  220. ; DS:SI: src2.
  221. ; ES:DI: src1 or dst.    -- careful, ES:DI used for two purposes.
  222.  
  223.     public _MakeRunSkipDump
  224.     STARTPROC _MakeRunSkipDump
  225.  
  226. MR_SRC1_SEG        = ARGB
  227. MR_SRC2_SEG        = ARGB+2
  228. MR_FINAL_PIXEL_ADDR = ARGB+4
  229. MR_DST_SEG        = ARGB+6
  230. MR_DST_ADDR        = ARGB+8    ; dst0 -- save so can calculate size.
  231. MR_DST_LIMIT        = ARGB+10    ; dstLimit => dstAddr musn't pass this.
  232. MR_N_BYTES_PTR        = ARGB+12
  233. MR_SRC_WIDTH        = ARGB+14
  234. MR_FINAL_ROW_ADDR   = ARGB+16
  235. MR_FINAL_ROW_WIDTH  = ARGB+18
  236. MR_IN_FINAL_ROW        = ARGB+20
  237. MR_SKIP_PERMITTED   = ARGB+22
  238. ; --- locals
  239. MR_SRC1_FAR    = -4    ; ES:DI when addressing src1.
  240. MR_DST_FAR    = -8    ; ES:DI when addressing dst.
  241. MR_MUST_STOP    = -9    ; BOOL mustStop.  Have reached end of src data.
  242. ;unused byte... MR_???        = -10    ; BOOL ???
  243. MR_X        = -12    ; current x-coordinate.
  244. MR_LARGE_SKIP_LIMIT = -14 ; At or beyond here, don't try to do large skip.
  245. MR_WAS_X    = -16    ; x-coordinate where op's data started.
  246. mLOCALS        =  16    ; Total local space to save.
  247.  
  248.     push    bp
  249.     mov    bp,sp
  250.     sub    sp,mLOCALS
  251.     push    si
  252.     push    di
  253.     push    es
  254.  
  255.  IF 0   ; debugging
  256.     mov    _TotBytes,0
  257.  ENDIF
  258. ; --- Simplify "incompressible" checking.  We don't care if we are
  259. ; slightly over-conservative.  7 allows 3B for long skip, 4B for any
  260. ; other op.  This allows us to not check at all on a short skip
  261. ; (a >4B series of short skips would never be done -- long skip done instead),
  262. ; and to check run or dump overhead without subtracting the size of the
  263. ; overhead.
  264.     sub    word ptr MR_DST_LIMIT[bp],7
  265.  
  266.  
  267. ; --- Simplify check of limit for "large skip" code.  The limit is determined
  268. ; by the need to have CLIP_X see the transition to the final scan row.
  269.     mov    dx,MR_FINAL_ROW_ADDR[bp]
  270.     sub    dx,MR_SRC_WIDTH[bp]    ; Paranoia -- a whole row before final.
  271.     sub    dx,4            ; Make sure CLIP_X gets a chance.
  272.     mov    MR_LARGE_SKIP_LIMIT[bp],dx
  273.  
  274.  
  275. ; --- Prepare far ptrs for "les di,...".
  276.     sub    di,di            ; SET src1.
  277.     mov    ax,MR_SRC1_SEG[bp]
  278.     mov    MR_SRC1_FAR+ADDR[bp],di
  279.     mov    MR_SRC1_FAR+SEGM[bp],ax
  280.     mov    di,MR_DST_ADDR[bp]    ; SET dst.  SET DI:dstAddr.
  281.     mov    ax,MR_DST_SEG[bp]
  282.     mov    MR_DST_FAR+ADDR[bp],di
  283.     mov    MR_DST_FAR+SEGM[bp],ax
  284.  
  285. ; --- ASSUME srcs start at Addr=0.    
  286.     sub    si,si            ; SET (DS:SI):src2.
  287.     push    ds            ; Save DS:DGROUP.
  288.     mov    ds,MR_SRC2_SEG[bp]    ; SET DS:dstSeg.  NOT DGROUP.
  289. ; --- DGROUP NOT ACCESSIBLE VIA DS BELOW.  USE SS IF NEED DGROUP. ---
  290.  
  291.     les    di,MR_DST_FAR[bp]    ; SET ES:DI:dst.
  292.     mov    ax,BMBODY_RUNSKIPDUMP
  293.     stosw                ; *(UWORD far *)dst++ =
  294.                     ;   2-byte header containing type.
  295.     mov    MR_DST_FAR+ADDR[bp],di    ; Save dstAddr, so DI can be re-used.
  296.  
  297.     les    di,MR_SRC1_FAR[bp]    ; *** SET ES:DI:src1 for loops ***
  298.  
  299.     sub    dx,dx            ; 0.
  300.     mov    MR_X[bp],dx        ; "x=0;"
  301.     mov    MR_MUST_STOP[bp],dl    ; "mustStop = FALSE;"
  302.  
  303. notInASequence:
  304.     sub    cx,cx            ; CX:wordCnt=0.
  305.  
  306. ; ----------------------- Dump -------------------------------------------
  307. ; ASSUME ES:DI: src1.
  308. ; "pixel" must be set when jump to beDump with "wordCnt != 0".
  309. beDump:
  310.     mov    dx,MR_X[bp]        ;
  311.     sub    dx,cx            ; CX:wordCnt.
  312.     jge    Dxw
  313.     add    dx,MR_SRC_WIDTH[bp]    ; started on previous line
  314. Dxw:    mov    MR_WAS_X[bp],dx
  315.  
  316.     sub    bx,bx            ; SET BL:skipInDump=0, BH:runInDump=0.
  317.     or    cx,cx            ; test CX:wordCnt.
  318.     jz    DnoCnt
  319.     inc    bh            ; BH:runInDump.  Any pixel is run==1.
  320. DnoCnt:
  321. inDump:
  322.     mov    dx,MR_X[bp]
  323.     cmp    dx,MR_SRC_WIDTH[bp]
  324.     jne    DnoClip
  325.     call    ClipX            ; "CLIP_X(stopDump);"
  326.     jnz    stopDump
  327. DnoClip:
  328.  
  329.     mov    ah,al            ; AH,AL: "runPix = pixel;"
  330.     lodsb                ; "pixel = *src2++;"    Get&count byte
  331.     inc    word ptr MR_X[bp]    ; "x++;"
  332.     inc    cx            ; CX: "wordCnt++;"
  333.  
  334.     cmp    al,es:[di]        ; AL:pixel.  ES:DI:src1.
  335.     je    DSkip            ; "if (pixel != *src1)"
  336.     mov    bl,0ffh            ;   "-1" & inc below => "skipInDump=0"
  337. DSkip:
  338.     inc    bl            ; BL: "skipInDump++;"
  339.     inc    di            ; DI: "src1++;"
  340.  
  341.     cmp    al,ah            ; "if (pixel != runPix)"
  342.     je    DRun
  343.     sub    bh,bh            ;   "0" & inc below => "runInDump=1"
  344.                     ;   Any pixel is a run of 1.
  345. DRun:
  346.     inc    bh            ; BH: "runInDump++;"
  347.  
  348.     cmp    bl,MIN_SKIP        ; "if (skipInDump == MIN_SKIP"
  349.     jne    DnoSkip
  350.     test    byte ptr MR_SKIP_PERMITTED[bp],1  ; "  &&  skipPermitted)"
  351.     jz    DnoSkip
  352. ; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_SKIP);"
  353.     push    bx
  354.     push    cx
  355.     mov    bx,si            ; SET BX:param1.  SI:src2Addr.
  356.     sub    bx,cx            ; CX:wordCnt.
  357.     sub    cx,MIN_SKIP        ; SET CX:param2 = CX:wordCnt-MIN_SKIP.
  358.     call    PutDump
  359.     pop    cx
  360.     pop    bx
  361.  
  362.     mov    cx,MIN_SKIP        ; CX:wordCnt.
  363.     jmp    beSkip
  364. DnoSkip:
  365.  
  366.     cmp    bh,MIN_RUN        ; "if (runInDump == MIN_RUN)"
  367.     jne    noRID
  368. ; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_RUN);"
  369.     push    bx
  370.     push    cx
  371.     mov    bx,si            ; SET BX:param1.  SI:src2Addr.
  372.     sub    bx,cx            ; CX:wordCnt.
  373.     sub    cx,MIN_RUN        ; SET CX:param2 = CX:wordCnt-MIN_RUN.
  374.     call    PutDump
  375.     pop    cx
  376.     pop    bx
  377.  
  378.     mov    cx,MIN_RUN        ; CX:wordCnt.
  379.     jmp    short beRun
  380. noRID:
  381.  
  382. ; --- Byte still in Dump.
  383.     cmp    cx,MAX_LONG_DUMP    ; "if (wordCnt == MAX_LONG_DUMP)"
  384.     jne    inDump
  385. stopDump:
  386. ; --- "PUT_DUMP(src2-wordCnt, wordCnt);"
  387.     push    bx
  388.     push    cx
  389.     mov    bx,si            ; SET BX:param1.  SI:src2Addr.
  390.     sub    bx,cx            ; CX:wordCnt.
  391.     ;                ; SET CX:param2 = CX:wordCnt.
  392.     call    PutDump
  393.     pop    cx
  394.     pop    bx
  395.  
  396.     test    byte ptr MR_MUST_STOP[bp],1
  397.     jnz    Dstop
  398.     jmp    notInASequence
  399. Dstop:    jmp    beStop
  400.  
  401.  
  402. ; ----------------------- Run -------------------------------------------
  403. ; ASSUME ES:DI: src1.
  404. beRun:
  405.     mov    dx,MR_X[bp]        ;
  406.     sub    dx,cx            ; CX:wordCnt.
  407.     jge    Rxw
  408.     add    dx,MR_SRC_WIDTH[bp]    ; started on previous line
  409. Rxw:    mov    MR_WAS_X[bp],dx
  410.  
  411.     sub    bx,bx            ; SET BL:skipInDump=0.
  412.     mov    ah,al            ; "runPix = pixel;"
  413. inRun:
  414.     mov    dx,MR_X[bp]
  415.     cmp    dx,MR_SRC_WIDTH[bp]
  416.     jne    RnoClip
  417.     call    ClipX            ; "CLIP_X(stopRun);"
  418.     jnz    stopRun
  419. RnoClip:
  420.  
  421.     lodsb                ; "pixel = *src2++;"    Get&count byte
  422.     inc    word ptr MR_X[bp]    ; "x++;"
  423.     inc    cx            ; CX: "wordCnt++;"
  424.  
  425.     cmp    al,es:[di]        ; AL:pixel.  ES:DI:src1.
  426.     je    RSkip            ; "if (pixel != *src1)"
  427.     mov    bl,0ffh            ;   "-1" & inc below => "skipInDump=0"
  428. RSkip:
  429.     inc    bl            ; BL: "skipInDump++;"
  430.     inc    di            ; DI: "src1++;"
  431.  
  432. ; Note: check for byte runnable comes later.
  433.  
  434.     cmp    bl,MIN_RUN_SKIP        ; "if (skipInDump == MIN_RUN_SKIP"
  435.     jne    RnoSkip
  436.     test    byte ptr MR_SKIP_PERMITTED[bp],1  ; "  &&  skipPermitted)"
  437.     jz    RnoSkip
  438.     sub    cx,MIN_RUN_SKIP        ; retract skip bytes from wordCnt.
  439. ; --- "PUT_RUN(wordCnt, runPix);"
  440.     call    PutRun            ; CX:wordCnt, AH:runPix.  Must Preserve.
  441.  
  442.     mov    cx,MIN_RUN_SKIP        ; CX:wordCnt.
  443.     jmp    short beSkip
  444. RnoSkip:
  445.  
  446.     cmp    al,ah            ; "if (pixel != runPix)"
  447.     je    Rrun
  448.     dec    cx            ; Retract pixel from Run.
  449. ; --- "PUT_RUN(wordCnt, runPix);"
  450.     call    PutRun            ; CX:wordCnt, AH:runPix.  Must Preserve.
  451.  
  452.     mov    cx,1            ; CX:wordCnt.
  453.     jmp    beDump
  454.  
  455. ; --- Byte runnable.
  456. Rrun:
  457.     cmp    cx,MAX_LONG_RUN    ; "if (wordCnt == MAX_LONG_RUN)"
  458.     jne    inRun
  459. stopRun:
  460. ; --- "PUT_RUN(wordCnt, runPix);"
  461.     call    PutRun            ; CX:wordCnt, AH:runPix.  Must Preserve.
  462.  
  463.     test    byte ptr MR_MUST_STOP[bp],1
  464.     jnz    Dstop            ; ("jmp beStop" was out of range.)
  465.     jmp    notInASequence
  466.  
  467.  
  468. ; ----------------------- Skip -------------------------------------------
  469. beSkip:
  470.  
  471. ; ---------------- Attempt to quickly skip a long ways forward.
  472.     mov    dx,MR_LARGE_SKIP_LIMIT[bp]
  473.     sub    dx,si
  474.     jb    inSkip0            ; Too close to end.
  475.  
  476.     push    cx            ; Hold CX:wordCnt.
  477.     mov    cx,dx            ; Permit skip up to skipLimit.
  478.     shr    cx,1            ; As # words.
  479.     mov    dx,cx            ; SET DX: # words to cnt down.
  480.     jcxz    skippedAll
  481.     repe cmpsw
  482.  
  483.     je    skippedAll        ; last words eql; cnt stopped us.
  484.     sub    si,2            ; Retract the non-matching word.
  485.     sub    di,2
  486.     inc    cx
  487. skippedAll:
  488.     sub    dx,cx            ; # skip words found.
  489.     shl    dx,1            ; # skip bytes found.
  490.  
  491.     pop    cx            ; Restore CX:wordCnt.
  492.     add    cx,dx            ; wordCnt now reflects new skip bytes.
  493.     add    dx,MR_X[bp]        ; x += bytes found, mod width.
  494. SmodX:    sub    dx,MR_SRC_WIDTH[bp]    ; force it to underflow.
  495.     jnb    SmodX
  496.     add    dx,MR_SRC_WIDTH[bp]    ; compensate for underflow.
  497. SxOk:    mov    MR_X[bp],dx
  498. ; ----------------
  499.     jmp    short inSkip
  500.  
  501.  
  502. ; --- Byte skippable.  Final Skip is NOT output prior to Stop.
  503. skippable:
  504.     inc    di            ; DI: "src1++;"
  505.  
  506. inSkip0:
  507.     mov    dx,MR_X[bp]
  508.     cmp    dx,MR_SRC_WIDTH[bp]
  509.     je    Sclip
  510. ; --- fall through to "inSkip".
  511.  
  512. inSkip:
  513.     lodsb                ; "pixel = *src2++;"    Get&count byte
  514.     inc    word ptr MR_X[bp]    ; "x++;"
  515.     inc    cx            ; CX: "wordCnt++;"
  516.  
  517.     cmp    al,es:[di]        ; AL:pixel.  ES:DI:src1.
  518.     je    skippable        ; "if (pixel != *src1)"
  519. ; --- Byte not skippable.  Put the Skip.  *** AX:temporary.***
  520. ; NOTE: Subtracted enough from dstLimit, that we're not bothering to
  521. ; check for incompressible (destination buffer overflow) on short skips.
  522.     inc    di            ; DI: "src1++;"
  523.     push    ax            ; Hold AX.  "jmp SOutDone" for POP.***
  524. ; IF CHANGE # regs pushed, must change SOutDone & Sincompressible.
  525.  
  526.     mov    MR_SRC1_FAR+ADDR[bp],di    ; Update src1Addr from DI.
  527.     les    di,MR_DST_FAR[bp]    ; SET ES:DI:dst.
  528.  
  529.     dec    cx            ; "wordCnt--;"    Retract pixel.
  530.  IF 0
  531.     call    DumpPutSkip
  532.  ENDIF
  533.     cmp    cx,MAX_SHORT_SKIP
  534.     ja    SnotShort
  535. ; --- One Short Skip.
  536.     mov    al,OP_SKIP        ; "*dst++ = OP_SKIP | wordCnt;"
  537.     or    al,cl
  538.     stosb
  539.     jmp    short SOutDone
  540.  
  541. SnotShort:
  542.     cmp    cx,2*MAX_SHORT_SKIP
  543.     ja    Slong
  544. ; --- Two Short Skips.
  545.     mov    al,OP_SKIP         ; "*dst++ = OP_SKIP | MAX_SHORT_SKIP;"
  546.     or    al,MAX_SHORT_SKIP
  547.     stosb
  548.     sub    cx,MAX_SHORT_SKIP    ; "wordCnt-= MAX_SHORT_SKIP;"
  549.     mov    al,OP_SKIP        ; "*dst++ = OP_SKIP | wordCnt;"
  550.     or    al,cl
  551.     stosb
  552.     jmp    short SOutDone
  553. Slong:
  554.     mov    dx,cx            ; SET DX:wordCnt0 = wordCnt.
  555. Slong0:    mov    cx,dx            ; "while (wordCnt0) {..."
  556.     jcxz    SOutDone
  557.     cmp    di,MR_DST_LIMIT[bp]    ; Check for incompressible.
  558.     ja    Sincompressible
  559.     cmp    cx,MAX_LONG_SKIP    ; "wordCnt = MIN(wordCnt0,MAX_LONG_SKIP);"
  560.     jbe    Sfits
  561.     mov    cx,MAX_LONG_SKIP
  562. Sfits:    sub    dx,cx            ; "wordCnt0 -= wordCnt;"
  563.     mov    al,LONG_OP        ; "*dst++ = LONG_OP;"
  564.     stosb
  565.     mov    ax,cx            ; "*((UWORD far *)dst++ = wordCnt;"
  566.     stosw
  567.     jmp    short Slong0
  568.  
  569. SOutDone:
  570.     mov    MR_DST_FAR+ADDR[bp],di    ; Update dstAddr.
  571.     les    di,MR_SRC1_FAR[bp]    ; SET ES:DI:src1.
  572.     pop    ax            ; Restore AX. ***
  573.     mov    cx,1            ; CX:wordCnt.
  574.     jmp    beDump
  575.  
  576. Sclip:    call    ClipX            ; "CLIP_X(beStop);"
  577.     jnz    beStop
  578.     jmp    short inSkip        ; Skip may be any length up to 64KB-1.
  579.  
  580. Sincompressible:
  581.     pop    ax            ; Match "push ax".
  582.     jmp    incompressible
  583.  
  584. ; ----------------------- Stop -------------------------------------------
  585. beStop:
  586.     mov    MR_SRC1_FAR+ADDR[bp],di    ; Update src1Addr from DI.
  587.     les    di,MR_DST_FAR[bp]    ; SET ES:DI:dst.
  588.     cmp    di,MR_DST_LIMIT[bp]    ; Check for incompressible.
  589.     ja    incompressible
  590.     mov    al,LONG_OP        ; "*dst++ = LONG_OP;"
  591.     stosb                ; Stop is "LongOp #0".
  592.     sub    ax,ax            ; 0.
  593.     stosw                ; "*(UWORD far *)dst++ = 0;"
  594.  
  595.     mov    ax,di            ; "*nBytesP = dst - dst0;"
  596.     sub    ax,MR_DST_ADDR[bp]
  597.     mov    bx,MR_N_BYTES_PTR[bp]
  598.     mov    ss:[bx],ax        ; ASSUME SS=DGROUP.
  599.  
  600.     mov    ax,1            ; RETURN TRUE.
  601.     jmp    short done
  602.  
  603. ; --- Body could not be compressed into given buffer size.
  604. ; Consider it incompressible.  (Actually, client may have given a small
  605. ; buffer, and may wish to re-try with a larger buffer.)
  606. incompressible:
  607.     sub    ax,ax            ; RETURN FALSE.
  608. done:
  609.     pop    ds            ; Restore DS: DGROUP.
  610.  
  611.     pop    es
  612.     pop    di
  613.     pop    si
  614.     mov    sp,bp
  615.     pop    bp
  616.     ret                ; FAR back to client.
  617.  
  618.  
  619. ; ------ CLIP_X() -----------------------------------------------------------
  620. ; No parameters, returns flags according to "test inFinalRow".
  621. ; DX: -- temporary.  ASSUME caller allows destruction.
  622. ; NOTE: moved per-pixel test into each caller, to save time per pixel.
  623. ; Therefore, must already know at line end when call ClipX.
  624. ClipX:    mov    word ptr MR_X[bp],0
  625.     test    byte ptr MR_IN_FINAL_ROW[bp],1
  626.     jz    notDone
  627.     mov    byte ptr MR_MUST_STOP[bp],1
  628.  IF 0
  629.     call    DumpFinal
  630.  ENDIF
  631.     mov    dx,1
  632.     or    dx,dx            ; clear zero flag.
  633.     retn                ; NEAR.
  634. notDone: cmp    si,MR_FINAL_ROW_ADDR[bp]  ; "if (src2Addr == finalRowAddr)"
  635.     jne    notStartingLastLine
  636.     mov    dx,MR_FINAL_ROW_WIDTH[bp] ; "w = finalRowWidth;"
  637.     mov    MR_SRC_WIDTH[bp],dx
  638.     mov    byte ptr MR_IN_FINAL_ROW[bp],1      ; "inFinalRow = TRUE;"
  639. notStartingLastLine:
  640.  IF 0
  641.     call    DumpClipX
  642.  ENDIF
  643.     sub    dx,dx            ; set zero flag.
  644.     retn                ; NEAR.
  645.  
  646.  
  647. ; ------ Assembly level routines, with same registers & BP as above, except:
  648. ; AX: -- temporary.  Each routine must SAVE/RESTORE.
  649. ; DX: -- temporary.  ASSUME caller allows destruction.
  650. ; REMEMBER, DS:src2Seg, NOT DGROUP.
  651. ; REMEMBER, ES:DI: src1.  DI must be updated to MR_SRC1_FAR+ADDR[bp], if
  652. ;   need to use it for dst.
  653.  
  654.  
  655. ; ------ PutRun(CX:wordCnt, AH:runPix) --------------------------------------
  656. ; Must Preserve all registers, including parameters.
  657. PutRun:
  658.     jcxz    noRun
  659.  IF 0
  660.     call    DumpPutRun
  661.  ENDIF
  662.     push    ax            ; Hold AX.  Last, so can access runPix.
  663. ; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible.
  664.  
  665.     mov    MR_SRC1_FAR+ADDR[bp],di    ; Update src1Addr from DI.
  666.     les    di,MR_DST_FAR[bp]    ; SET ES:DI:dst.
  667.     cmp    di,MR_DST_LIMIT[bp]    ; Check for incompressible.
  668.     ja    Rincompressible
  669.     cmp    cx,MAX_SHORT_RUN    ;
  670.     ja    lRun            ; "wordCnt > MAX_SHORT_RUN"
  671.     mov    ax,MR_WAS_X[bp]
  672.     add    ax,cx
  673.     cmp    ax,MR_SRC_WIDTH[bp]
  674.     ja    lRun            ; "CROSSED_W(wordCnt)"
  675.     mov    al,OP_RUN        ; "*dst++ = OP_RUN;"
  676.     stosb
  677.     mov    al,cl            ; "*dst++ = wordCnt;"
  678.     stosb
  679.     jmp    short rBody
  680. lRun:                    ; longRun op.
  681.     mov    al,LONG_OP        ; "*dst++ = LONG_OP;"
  682.     stosb
  683.     mov    ax,cx               ; "*((UWORD far *)dst++ =      "
  684.     or    ah,LONG_RUN        ; "   (LONG_RUN<<8) | wordCnt);"
  685.     stosw
  686. rBody:
  687.     pop    ax            ; ACCESS AH:runPix.
  688.     push    ax
  689.     mov    al,ah
  690.     stosb                ; "*dst++ = runPix;"
  691.  
  692.     mov    MR_DST_FAR+ADDR[bp],di    ; Update dstAddr.
  693.     les    di,MR_SRC1_FAR[bp]    ; SET ES:DI:src1.
  694.  
  695.     pop    ax            ; Restore AX.
  696. noRun:    retn                ; NEAR.
  697.  
  698. Dincompressible:
  699.     ; NOTE: since we're throwing everything away, doesn't matter that
  700.     ; bx & cx aren't the top two items at this point.
  701.     pop    ax            ; Balance CALLER'S PUSH BX & CX.
  702.     pop    ax
  703. Rincompressible:
  704.     pop    ax            ; Balances "push ax".
  705.     pop    ax            ; Remove (near) return address.
  706.     jmp    short incompressible
  707.  
  708. ; --- PutDump(DS:BX:body, CX:cnt).
  709. ; BX: param1.         ASSUME caller allows destruction.
  710. ; CX: param2.         ASSUME caller allows destruction.
  711. ; Dump's data is at "body" -- a sequence of pixels in src2seg.
  712. ; ALL CALLER'S MUST PUSH BX & CX, AND ONLY those registers, so that
  713. ;  "Dincompressible" will pop correct #words.
  714. PutDump:
  715.     jcxz    noDump            ; No data to dump.
  716.  IF 0
  717.     call    DumpPutDump
  718.  ENDIF
  719.     push    ax            ; Hold AX.
  720. ; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible.
  721.  
  722.     mov    MR_SRC1_FAR+ADDR[bp],di    ; Update src1Addr from DI.
  723.     les    di,MR_DST_FAR[bp]    ; SET ES:DI:dst.
  724.  
  725.     mov    dx,MR_DST_LIMIT[bp]    ; Check for incompressible.
  726.     sub    dx,cx
  727.     jb    Dincompressible        ; (underflow -- "dstLimit < wordCnt")
  728.     cmp    di,dx
  729.     ja    Dincompressible        ; "dstAddr > dstLimit-wordCnt"
  730.             ; "Rinc..." because "incompressible" was out of range.
  731.             ; It must be same condition test ("ja")!
  732.  
  733.     cmp    cx,MAX_SHORT_DUMP    ;
  734.     ja    lDump            ; "cnt > MAX_SHORT_DUMP"
  735.     mov    ax,MR_WAS_X[bp]
  736.     add    ax,cx
  737.     cmp    ax,MR_SRC_WIDTH[bp]
  738.     ja    lDump            ; "CROSSED_W(cnt)"
  739.     mov    al,OP_DUMP        ; "*dst++ = OP_DUMP | cnt;"
  740.     add    al,cl
  741.     stosb
  742.     jmp    short dBody
  743. lDump:                    ; longDump op.
  744.     mov    al,LONG_OP        ; "*dst++ = LONG_OP;"
  745.     stosb
  746.     mov    ax,cx            ; "*((UWORD far *)dst++ =   "
  747.     or    ah,LONG_DUMP        ; "   (LONG_DUMP<<8) | cnt);"
  748.     stosw
  749. dBody:
  750.     xchg    bx,si            ; Hold SI:src2.  SET BX:body.
  751.     rep movsb            ; DS:SI:body, ES:DI:dst, CX:cnt.
  752.                     ; Note: dst is ++ past the new data.
  753.     xchg    bx,si            ; Restore SI:src2.
  754.  
  755.     mov    MR_DST_FAR+ADDR[bp],di    ; Update dstAddr.
  756.     les    di,MR_SRC1_FAR[bp]    ; SET ES:DI:src1.
  757.     pop    ax            ; Restore AX.
  758. noDump:    retn                ; NEAR.
  759.  
  760.  IF 0    ; debugging
  761. DumpPutRun:
  762.     push    ds
  763.     push    es
  764.     push    ax
  765.     push    bx
  766.     push    cx
  767.     push    dx
  768.     mov    al,ah
  769.     sub    ah,ah
  770.     push    ax
  771.     push    cx
  772.     mov    ax,ss
  773.     mov    ds,ax
  774.     mov    es,ax
  775.     lea    ax,DGROUP:runMsg
  776.     push    ax
  777.     test    _doDump,0ffh
  778.     jz    noR
  779.     add     _TotBytes,cx
  780.     call    _printf
  781. noR:
  782.     add    sp,6
  783.     pop    dx
  784.     pop    cx
  785.     pop    bx
  786.     pop    ax
  787.     pop    es
  788.     pop    ds
  789.     retn
  790.  
  791. DumpPutDump:
  792.     push    ds
  793.     push    es
  794.     push    ax
  795.     push    bx
  796.     push    cx
  797.     push    dx
  798.     push    cx
  799.     mov    ax,ss
  800.     mov    ds,ax
  801.     mov    es,ax
  802.     lea    ax,DGROUP:dumpMsg
  803.     push    ax
  804.     test    _doDump,0ffh
  805.     jz    noD
  806.     add     _TotBytes,cx
  807.     call    _printf
  808. noD:
  809.     add    sp,4
  810.     pop    dx
  811.     pop    cx
  812.     pop    bx
  813.     pop    ax
  814.     pop    es
  815.     pop    ds
  816.     retn
  817.  
  818. DumpPutSkip:
  819.     push    ds
  820.     push    es
  821.     push    ax
  822.     push    bx
  823.     push    cx
  824.     push    dx
  825.     push    cx
  826.     mov    ax,ss
  827.     mov    ds,ax
  828.     mov    es,ax
  829.     lea    ax,DGROUP:skipMsg
  830.     push    ax
  831.     test    _doDump,0ffh
  832.     jz    noS
  833.     add     _TotBytes,cx
  834.     call    _printf
  835. noS:
  836.     add    sp,4
  837.     pop    dx
  838.     pop    cx
  839.     pop    bx
  840.     pop    ax
  841.     pop    es
  842.     pop    ds
  843.     retn
  844.  
  845. DumpClipX:
  846.     push    ds
  847.     push    es
  848.     push    ax
  849.     push    bx
  850.     push    cx
  851.     push    dx
  852.     mov    ax,ss
  853.     mov    ds,ax
  854.     mov    es,ax
  855.     push    di            ; dest
  856.     lea    ax,DGROUP:clipMsg
  857.     push    ax
  858.     test    _doDump,0ffh
  859.     jz    noC
  860.     call    _printf
  861. noC:
  862.     add    sp,4
  863.     pop    dx
  864.     pop    cx
  865.     pop    bx
  866.     pop    ax
  867.     pop    es
  868.     pop    ds
  869.     retn
  870.  
  871. DumpFinal:
  872.     push    ds
  873.     push    es
  874.     push    ax
  875.     push    bx
  876.     push    cx
  877.     push    dx
  878.     mov    ax,ss
  879.     mov    ds,ax
  880.     mov    es,ax
  881.     mov    ax,MR_FINAL_ROW_WIDTH[bp]
  882.     push    ax
  883.     push    di            ; dest
  884.     lea    ax,DGROUP:finalMsg
  885.     push    ax
  886.     test    _doDump,0ffh
  887.     jz    noF
  888.     call    _printf
  889. noF:
  890.     add    sp,6
  891.     pop    dx
  892.     pop    cx
  893.     pop    bx
  894.     pop    ax
  895.     pop    es
  896.     pop    ds
  897.     retn
  898.  ENDIF  ; Debugging
  899.     ENDPROC _MakeRunSkipDump
  900.  ENDIF    ; RunSkipDump format.
  901.  
  902.  
  903.  IF 0    ; simple dump format.
  904. ;-----------------------------------------------------------------
  905. ; void AsmPlayDelta(UWORD picSeg, deltaSeg, deltaAddr, deltaBytes);
  906. ; Finishes playing the current delta-encoding format.
  907. ;-----------------------------------------------------------------
  908.  
  909.     public _AsmPlayDelta
  910.     STARTPROC _AsmPlayDelta
  911.  
  912. APD_PIC_SEG    = ARGB
  913. APD_DELTA_SEG    = ARGB+2
  914. APD_DELTA_ADDR    = ARGB+4
  915. APD_DELTA_BYTES    = ARGB+6
  916.  
  917.     push    bp
  918.     mov    bp,sp
  919.     push    si
  920.     push    di
  921.     push    es
  922.  
  923.     mov    si,APD_DELTA_ADDR[bp]
  924.     mov    dx,APD_DELTA_BYTES[bp]
  925.     mov    es,APD_PIC_SEG[bp]
  926.  
  927.     push    ds            ; Save DS:DGROUP.
  928.     mov    ds,APD_DELTA_SEG[bp]    ; SET DS:deltaSeg.  NOT DGROUP.
  929.  
  930.     jmp    short more        ; In case no data.
  931.  
  932. runLoop:
  933.     lodsw
  934.     mov    di,ax            ; SET DI:picAddr
  935.     lodsw
  936.     mov    cx,ax            ; SET CX:runCount
  937.     rep movsb            ; far_movmem
  938.  
  939. more:    cmp    si,dx            ; while (deltaAddr < deltaBytes)
  940.     jb    runLoop
  941.  
  942.     pop    ds            ; Restore DS:DGROUP.
  943.  
  944.     pop    es
  945.     pop    di
  946.     pop    si
  947.     pop    bp
  948.     ret
  949.  
  950.     ENDPROC _AsmPlayDelta
  951.  
  952.  
  953. ;-----------------------------------------------------------------
  954. ; UWORD MakeDeltaSequence(UWORD picSeg, prevSeg, minAddr, maxAddr,
  955. ;             deltaSeg, deltaAddr, limitAddr);
  956. ;
  957. ; Given a sequence of bytes in the same position in two images,
  958. ; create a delta-description to convert one image to the other.
  959. ;
  960. ; Puts the delta at (deltaSeg,deltaAddr).
  961. ; RETURNS "deltaBytes" -- # bytes to describe the delta, INCLUDING
  962. ; the initial "deltaAddr" value.
  963. ; "limitAddr" is offset into deltaSeg that may not be overwritten.
  964. ; RETURNS "-1" if doesn't fit.
  965. ;-----------------------------------------------------------------
  966.  
  967. DOESNT_FIT    = -1
  968.  
  969. O_PIC_SEG    = ARGB
  970. O_PREV_SEG    = ARGB+2
  971. O_MIN_ADDR    = ARGB+4
  972. O_MAX_ADDR    = ARGB+6
  973. O_DELTA_SEG    = ARGB+8
  974. O_DELTA_ADDR    = ARGB+10
  975. O_LIMIT_ADDR    = ARGB+12
  976.  
  977.     public      _MakeDeltaSequence
  978.     STARTPROC _MakeDeltaSequence
  979.  
  980.     push    bp
  981.     mov    bp,sp
  982.     push    si
  983.     push    di
  984.     push    es
  985.  
  986.     mov    si,O_MIN_ADDR[bp]    ; SET SI:picAddr = minAddr.
  987.     mov    es,O_PREV_SEG[bp]    ; SET ES:prevSeg
  988.     mov    dx,O_DELTA_SEG[bp]    ; SET DX:deltaSeg
  989.     mov    di,O_DELTA_ADDR[bp]    ; SET DI:deltaAddr
  990.  
  991.     push    ds            ; Save DS:DGROUP.
  992.     mov    ds,O_PIC_SEG[bp]    ; SET DS:picSeg.  NOT DGROUP.
  993.  
  994. ; --- Not in a run.  Look for differences.
  995.     sub    cx,cx            ; SET CX:runCount.
  996.     sub    bx,bx            ; SET BX:gapSize.
  997.     jmp    short growGap0
  998.  
  999. gapStarted:
  1000. growGap:
  1001.     inc    bx            ; BX:gapSize.
  1002.     inc    si
  1003. growGap0:
  1004.     cmp    si,O_MAX_ADDR[bp]
  1005.     ja    endWhileInGap
  1006.  
  1007. ; --- Cmp pic byte to prev byte.
  1008.     mov    al,es:[si]        ; ES:prevSeg, SI:picAddr
  1009.     cmp    al,[si]            ; DS:picSeg,  SI:picAddr
  1010.     je    growGap
  1011.  
  1012. ; --- A run is starting.  Determine whether to append to previous run,
  1013. ;    or to output previous run.
  1014.     jcxz    noPreviousRun        ; So won't append initial gap to
  1015.                     ; non-existent run.
  1016.  
  1017.     cmp    bx,4            ; BX:gapSize
  1018.     jb    smallGap
  1019.  
  1020. endWhileInGap:
  1021.     jcxz    done        ; NO RUN EVER FOUND.
  1022. ; --- Output previous run. ---
  1023.  
  1024.     mov    ax,di        ; Test whether would reach limitAddr.
  1025.     add    ax,4        ; Run's addr & count.
  1026.     add    ax,cx        ; runCount.
  1027.     cmp    ax,O_LIMIT_ADDR[bp]
  1028.     jb    fits
  1029.     mov    ax,DOESNT_FIT    ; RETURN "DOESNT_FIT".
  1030.     jmp    short fail
  1031.  
  1032. fits:
  1033.     mov    ax,es
  1034.     xchg    ax,dx
  1035.     mov    es,ax        ; SET ES:deltaSeg, DX:prevSeg
  1036.  
  1037.     sub    si,bx        ; Move back past gap.
  1038.     sub    si,cx        ; SET SI:runAddr = picAddr - runCount
  1039.     mov    ax,si        ; *(WORD)(deltaSeg,deltaAddr)= runAddr,
  1040.     stosw            ; deltaAddr += 2.
  1041.     mov    ax,cx        ; *(WORD)(deltaSeg,deltaAddr)= runCount,
  1042.     stosw                 ; deltaAddr += 2.
  1043.     rep movsb    ; far_movmem picSeg|Addr => deltaSeg|Addr,
  1044.             ; runCount bytes.  When done, SI:picAddr set past run,
  1045.             ; CX:runCount = 0.
  1046.     add    si,bx        ; Move forward over gap.
  1047.     mov    ax,es
  1048.     xchg    ax,dx
  1049.     mov    es,ax        ; SET ES:prevSeg, DX:deltaSeg
  1050.  
  1051.     cmp    si,O_MAX_ADDR[bp]    ; Extra check saved a few code bytes.
  1052.     ja    done
  1053.  
  1054.     jmp    short gapConsumed
  1055.  
  1056. smallGap:
  1057.     add    cx,bx            ; Append gap to run.
  1058. ;    jmp    short gapConsumed
  1059.     
  1060. noPreviousRun:
  1061. gapConsumed:
  1062.     sub    bx,bx            ; SET BX:gapSize
  1063.  
  1064. ; --- When reach here, have already found one byte of run.
  1065. ;     ASSUME SI:picAddr still pointing at byte, CX:runCount already is zero.
  1066.  
  1067. continueRun:
  1068.     inc    si                ; Move SI:picAddr past byte of run.
  1069.     inc    cx            ; CX:runCount.
  1070.     cmp    si,O_MAX_ADDR[bp]
  1071.     ja    endWhileInRun
  1072.  
  1073.     mov    al,es:[si]        ; ES:prevSeg, SI:picAddr
  1074.     cmp    al,[si]            ; DS:picSeg,  SI:picAddr
  1075.     jne    continueRun
  1076. endWhileInRun:
  1077.     jmp    short gapStarted    ; SI points to first byte of gap.
  1078.                     ; BX:gapSize = 0.
  1079.  
  1080. done:
  1081.     mov    ax,di            ; RETURN deltaBytes = DI:deltaAddr.
  1082. fail:
  1083.     pop    ds            ; Restore DS:DGROUP.
  1084.  
  1085.     pop    es
  1086.     pop    di
  1087.     pop    si
  1088.     pop    bp
  1089.     ret
  1090.  
  1091.     ENDPROC _MakeDeltaSequence
  1092.  ENDIF    ; simple dump format.
  1093.  
  1094.     ENDPS anima
  1095.     end
  1096.